package com.wkq.net

import android.content.Context
import android.text.TextUtils
import com.google.gson.GsonBuilder
import com.wkq.net.callback.FileDownCallback
import com.wkq.net.gson.StringTypeAdapter
import com.wkq.net.interceptor.HttpHeadersInterceptor
import com.wkq.net.interceptor.ProgressResponseBody
import com.wkq.net.util.DownSecretUtil
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.functions.Consumer
import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.util.concurrent.TimeUnit


/**
 *
 *@Author: wkq
 *
 *@Time: 2025/4/8 17:06
 *
 *@Desc:文件下载工具类
 */
object RetrofitFileDownUtil {
    private var retrofit: Retrofit? = null


    private fun getInstance(): Retrofit {
        if (retrofit == null) {
            val okHttpClientBuilder = OkHttpClient().newBuilder()
            okHttpClientBuilder.writeTimeout(5 * 1000, TimeUnit.MILLISECONDS)
            okHttpClientBuilder.connectTimeout(5 * 1000, TimeUnit.MILLISECONDS)
            okHttpClientBuilder.addInterceptor(
                HttpHeadersInterceptor(RetrofitNetConfig.getInstance().getNetHeader())
            )
            retrofit = Retrofit.Builder().client(okHttpClientBuilder.build())
                .baseUrl("https://www.google.com/")//设置BASEURL(以/结尾)
                .addConverterFactory(
                    GsonConverterFactory.create(
                        GsonBuilder().registerTypeAdapter(String::class.java, StringTypeAdapter())
                            .create()
                    )
                )
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .build()
        }

        return retrofit!!
    }


    fun <T> create(service: Class<T>): T {
        return getInstance().create(service)
    }

    /**
     * 正常请求
     * @receiver Observable<BaseModel<T>>
     * @param dataCallback DataCallback<T>
     */
    fun <ResponseBody> Observable<okhttp3.ResponseBody>.request(
        context: Context, url: String?="", fileDir: String? = "",
        callback: FileDownCallback? = null
    ): Disposable {

        if (TextUtils.isEmpty(url)) callback?.onFail(-1, "url is null")
        val onNextConsumer: Consumer<String> = Consumer { baseModel ->
            callback?.success(baseModel)
        }
        // 定义 onError 消费者，处理错误情况
        val onErrorConsumer: Consumer<Throwable> = Consumer { error ->
            if (error is HttpException) {
                val ex: HttpException = error
                callback?.onFail(ex.code(), ex.message)
            } else {
                callback?.onFail(-1, error.message ?: "")
            }
        }

        return this.subscribeOn(Schedulers.io())
            .map {
                val res = ProgressResponseBody(it, callback)
                var dirPath: String? = ""
                if (!TextUtils.isEmpty(fileDir)) {
                    if (!File(fileDir).exists()) {
                        File(fileDir).mkdir()
                    }
                    dirPath = fileDir
                } else {
                    val dir = RetrofitNetConfig.getInstance().getCacheDownFilePath(context)
                    if (!File(dir).exists()) {
                        File(dir).mkdir()
                    }
                    dirPath = dir
                }


                return@map writeResponseBodyToDisk(
                    res, dirPath + File.separator + DownSecretUtil.getMD5Result(url)
                );
            }
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(onNextConsumer, onErrorConsumer)
    }

    @Throws(IOException::class)
    private fun writeResponseBodyToDisk(body: ResponseBody, filePath: String): String {
        var inputStream: InputStream? = null
        var outputStream: FileOutputStream? = null
        try {
            val file = File(filePath)

            val fileReader = ByteArray(4096)
            inputStream = body.byteStream()
            outputStream = FileOutputStream(file)
            while (true) {
                val read = inputStream.read(fileReader)
                if (read == -1) {
                    break
                }
                outputStream.write(fileReader, 0, read)
            }
            outputStream.flush()
            return filePath
        } finally {
            inputStream?.close()
            outputStream?.close()
        }
    }


}